package com.xunlai.infra.permission.manager.authority.web;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.google.re2j.Pattern;
import com.xunlai.infra.permission.business.service.SmsService;
import com.xunlai.infra.permission.business.util.RandomUtils;
import com.xunlai.infra.permission.common.exception.ExceptionCodeEnum;
import com.xunlai.infra.permission.common.exception.PermissionBusinessException;
import com.xunlai.infra.permission.common.security.TenantUser;
import com.xunlai.infra.permission.manager.web.service.UserMemberService;
import com.xunlai.infra.permission.manager.web.vo.BaseResponse;
import com.xunlai.infra.permission.manager.web.vo.login.RegisterReqVo;
import com.xunlai.infra.permission.manager.web.vo.login.SendSmsCodeReqVo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author liang
 * @date 12/5/22 5:12 PM
 */
@Controller
public class LoginController {

    private static final String MOBILE_PATTERN = "^[1](([3|5|8][\\d])|([4][4,5,6,7,8,9])|([6][2,5,6,7])|([7][^9])|([9][1,8,9]))[\\d]{8}$";
    private CaptchaStorage captchaStorage;

    private CaptchaStorage smsCaptchaStorage;

    private UserMemberService userMemberService;

    private SmsService smsService;

    @GetMapping("/login")
    public String login() {
        return "login";
    }


    @GetMapping("/login/code")
    @ResponseBody
    public BaseResponse<String> code(){
        return BaseResponse.success("/api/v1/login/captcha");
    }

    @GetMapping("/login/captcha")
    public void captchaCode(HttpServletResponse response , HttpServletRequest request){
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100,30,4,25);
        response.setContentType("image/jpeg");
        response.setHeader("Pragma", "No-cache");
        try{
            lineCaptcha.write(response.getOutputStream());
            String code = lineCaptcha.getCode();
            captchaStorage.save(request.getSession().getId(),code);
//            request.getSession().setAttribute("piccode",code);
            response.getOutputStream().close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    @GetMapping("/userinfo")
    @ResponseBody
    public Object userInfo(HttpServletRequest request){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        TenantUser loginUser = (TenantUser) authentication.getPrincipal();
        Map<String,Object> result = new HashMap<>(4);
        result.put("sub",loginUser.getUsername());
        Collection<GrantedAuthority> authorities = loginUser.getAuthorities();
        List<String> roles = authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
        result.put("roles",roles);
        return result;
    }

    @PostMapping("/login/smsCode")
    @ResponseBody
    public BaseResponse<Boolean> sendSmsCaptcha(HttpServletRequest request,@RequestBody SendSmsCodeReqVo sendSmsCodeReqVo){
        //TODO
//        String smsCode = "2345";
        String smsCode = RandomUtils.getSixBitRandom();
        smsService.sendSms(sendSmsCodeReqVo.mobileNumber(),smsCode);
        smsCaptchaStorage.save(request.getSession().getId(),smsCode);
        return BaseResponse.success(true);
    }


    @PostMapping("/login/register")
    @ResponseBody
    public BaseResponse<Boolean> register(HttpServletRequest request,@RequestBody RegisterReqVo reqVo){
        String mobileNumber = reqVo.mobileNumber();
        if(!Pattern.matches(MOBILE_PATTERN,mobileNumber)){
            return BaseResponse.error(ExceptionCodeEnum.INVALID_MOBILE);
        }
        String smsCode = reqVo.smsCode();
        String smsCaptcha = smsCaptchaStorage.get(request.getSession(false).getId());
        if(smsCode == null || !smsCode.equals(smsCaptcha)){
            return BaseResponse.error(ExceptionCodeEnum.ERROR_SMS_CAPTCHA);
        }
        String password = reqVo.password();
        String repeatPassword = reqVo.repeatPassword();
        if(StringUtils.isBlank(password) || !password.equals(repeatPassword)){
            return  BaseResponse.error(ExceptionCodeEnum.DIFFER_PASSWORD);
        }
        //TODO
        try {
            userMemberService.registerUserMember(reqVo);
            return  BaseResponse.success(Boolean.TRUE);
        } catch (PermissionBusinessException e) {
            return BaseResponse.error(e.getCode(),e.getMsg());
        }finally {
            smsCaptchaStorage.remove(request.getSession(false).getId());
        }
    }
    @PostMapping("/login/password/forget")
    @ResponseBody
    public BaseResponse<Boolean> forgetPassword(HttpServletRequest request,@RequestBody RegisterReqVo reqVo){
        String mobileNumber = reqVo.mobileNumber();
        if(!Pattern.matches(MOBILE_PATTERN,mobileNumber)){
            return BaseResponse.error(ExceptionCodeEnum.INVALID_MOBILE);
        }
        String smsCode = reqVo.smsCode();
        String smsCaptcha = smsCaptchaStorage.get(request.getSession(false).getId());
        if(smsCode == null || !smsCode.equals(smsCaptcha)){
            return BaseResponse.error(ExceptionCodeEnum.ERROR_SMS_CAPTCHA);
        }
        String password = reqVo.password();
        String repeatPassword = reqVo.repeatPassword();
        if(StringUtils.isBlank(password) || !password.equals(repeatPassword)){
            return  BaseResponse.error(ExceptionCodeEnum.DIFFER_PASSWORD);
        }

        try {
            userMemberService.resetPassword(mobileNumber,password);
            return BaseResponse.success(true);
        } catch (PermissionBusinessException e){
            return BaseResponse.error(e.getCode(),false,e.getMsg());
        }
    }

    @Autowired
    @Qualifier("simpleCaptchaStorage")
    public void setCaptchaStorage(CaptchaStorage captchaStorage) {
        this.captchaStorage = captchaStorage;
    }

    @Autowired
    @Qualifier("smsCaptchaStorage")
    public void setSmsCaptchaStorage(CaptchaStorage smsCaptchaStorage) {
        this.smsCaptchaStorage = smsCaptchaStorage;
    }

    @Autowired
    public void setUserMemberService(UserMemberService userMemberService) {
        this.userMemberService = userMemberService;
    }

    @Autowired
    public void setSmsService(SmsService smsService) {
        this.smsService = smsService;
    }
}
